Column

Order Time vs Department

Column

24-Hour Order Trend on Instacart

Weekly Order Pattern on Instacart

---
title: "Dashboard"
output:
  flexdashboard::flex_dashboard:
    orientation: columns
    vertical_layout: fill
    source: embed
---

```{r setup, include=FALSE}
library(tidyverse)
library(flexdashboard)
library(plotly)
library(p8105.datasets)
```


```{r}
# Import data
data("instacart")
```

```{r}
# Preprocess the dataset
instacart_df = 
  instacart |>
  janitor::clean_names() |> 
  
  # handle missing values
  mutate(
    across(where(is.character), ~na_if(., ".")),
    across(where(is.character), ~na_if(., "NA")),
    across(where(is.character), ~na_if(., ""))
    ) |>
  
  # create derived variables
  mutate(
    # order time categories
    order_hour_category = case_when(
      order_hour_of_day >= 6 & order_hour_of_day < 12 ~ "Morning (6-12)",
      order_hour_of_day >= 12 & order_hour_of_day < 18 ~ "Afternoon (12-18)",
      order_hour_of_day >= 18 & order_hour_of_day < 22 ~ "Evening (18-22)",
      TRUE ~ "Night (22-6)"
    ),
    # Day of week names
    order_day_name = case_when(
      order_dow == 0 ~ "Sunday",
      order_dow == 1 ~ "Monday",
      order_dow == 2 ~ "Tuesday",
      order_dow == 3 ~ "Wednesday",
      order_dow == 4 ~ "Thursday",
      order_dow == 5 ~ "Friday",
      order_dow == 6 ~ "Saturday"
    ),
    # Weekend indicator
    is_weekend = if_else(order_dow %in% c(0, 6), "Weekend", "Weekday"),
    # Simplified department categories
    dept_category = case_when(
      department %in% c("produce", "dairy eggs") ~ "Fresh Foods",
      department %in% c("snacks", "frozen", "ice cream ice") ~ "Snacks & Frozen",
      department %in% c("bakery", "deli", "meat seafood") ~ "Bakery & Deli",
      department %in% c("beverages", "alcohol") ~ "Beverages",
      department %in% c("pantry", "dry goods pasta", "canned goods") ~ "Pantry Staples",
      TRUE ~ "Other"
    ),
    # change reorder type
    is_reordered = as.logical(reordered)
  ) |>
  
    select(
    # IDs
    order_id, product_id, user_id,
    # Product information
    product_name, aisle, department, dept_category,
    # Order timing
    order_hour_of_day, order_hour_category,
    order_dow, order_day_name, is_weekend,
    # Order characteristics
    order_number, add_to_cart_order,
    days_since_prior_order,
    # Reorder behavior
    reordered, is_reordered
  )
```


Column {data-width=450}
-----------------------------------------------------------------------

### Top 20 Most Popular Products

```{r}
top20_products =
  instacart_df |>
  count(product_name, sort = TRUE) |>
  slice_head(n = 20) |>
  mutate(
     product_name = fct_reorder(product_name, n)
     ) |>
  plot_ly(
    x = ~n,
    y = ~product_name, 
    type = "bar", 
    orientation = "h",
    marker = list(
      color = ~n,
      colorscale = list(
        c(0, "#FEF0D9"),
        c(0.5, "#FD8D3C"),
        c(1, "#D94701")
      ),
      line = list(color = "#8B4513", width = 1)
    ),
    text = ~paste0(product_name, "<br>Orders: ", n),
    hovertemplate = "<b>%{y}</b><br>Total Orders: %{x:,}<extra></extra>"
) |>
    layout(
      title = list(
        text = "<b>Top 20 Most Popular Products on Instacart</b>",
        font = list(size = 18)
      ),
      xaxis = list(
        title = "Number of Orders",
        titlefont = list(size = 14),
        gridcolor = "#E5E5E5"
      ),
      yaxis = list(
        title = "",
        titlefont = list(size = 14),
        tickfont = list(size = 11)
      ),
      plot_bgcolor = "#FAFAFA",
      paper_bgcolor = "white",
      margin = list(l = 200, r = 50, t = 80, b = 60),
      hovermode = "closest"
    )

top20_products
```


### Order Time vs Department

```{r}
time_dept_data =
  instacart_df |>
  count(order_hour_of_day, department) |>
  group_by(department) |>
  mutate(
    dept_total = sum(n),
    pct_of_dept = round(n / dept_total * 100, 1)
  ) |>
  ungroup()

scatterplot1 = 
  time_dept_data |>
  plot_ly(
    x = ~order_hour_of_day,
    y = ~department,
    color = ~department,
    type = "scatter",
    mode = "markers",
    size = ~ n,
    sizes = c(10, 400),
    marker = list(
      opacity = 0.7
    ),
    text = ~paste0(
      "<b>", department, "</b><br>",
      "Hour: ", order_hour_of_day, ":00<br>",
      "Orders: ", scales::comma(n), "<br>",
      "% of dept: ", pct_of_dept, "%"
    ),
    hovertemplate = "%{text}<extra></extra>"
  ) |>
  layout(
    title = list(
      text = "<b>Order Patterns: Time of Day vs Department</b><br><sub>Bubble size represents order volume</sub>",
      font = list(size = 16)
    ),
    xaxis = list(
      title = "Hour of Day (0-23)",
      titlefont = list(size = 14),
      tickmode = "linear",
      tick0 = 0,
      dtick = 2
    ),
    yaxis = list(
      title = "Department",
      titlefont = list(size = 14),
      tickfont = list(size = 11),
      categoryorder = "total ascending"
    )
  )

scatterplot1
```


Column {data-width=450}
-----------------------------------------------------------------------

### 24-Hour Order Trend on Instacart

```{r}
hourly_orders =
  instacart_df |>
  count(order_hour_of_day) |>
  mutate(
    pct_of_total = round(n / sum(n) * 100, 1)
  ) |>
  plot_ly(
    x = ~order_hour_of_day,
    y = ~n,
    type = "scatter",
    mode = "lines+markers",
    line = list(
      color = "#1f77b4",
      width = 3
    ),
    marker = list(
      size = 8,
      color = "#1f77b4",
      line = list(color = "white", width = 2)
    ),
    text = ~paste0(
      "Hour: ", order_hour_of_day, ":00<br>",
      "Orders: ", scales::comma(n), "<br>",
      "Percentage: ", pct_of_total, "%"
    ),
    hovertemplate = "%{text}<extra></extra>"
  ) |>
  layout(
    title = list(
      text = "<b>24-Hour Order Trend on Instacart</b><br><sub>Shopping patterns throughout the day</sub>",
      font = list(size = 16)
    ),
    xaxis = list(
      title = "Hour of Day",
      titlefont = list(size = 14),
      tickmode = "linear",
      tick0 = 0,
      dtick = 2,
      range = c(-0.5, 23.5),
      gridcolor = "#E5E5E5"
    ),
    yaxis = list(
      title = "Number of Orders",
      titlefont = list(size = 14),
      gridcolor = "#E5E5E5",
      tickformat = ","
    ),
    plot_bgcolor = "#FAFAFA",
    paper_bgcolor = "white",
    margin = list(l = 80, r = 50, t = 100, b = 60),
    hovermode = "x unified",
    shapes = list(
      # Adding a shaded area for peak hours
      list(
        type = "rect",
        x0 = 10, x1 = 16.5,
        y0 = 0, y1 = 1,
        yref = "paper",
        fillcolor = "rgba(255, 165, 0, 0.1)",
        line = list(width = 0),
        layer = "below"
      )
    ),
    annotations = list(
      list(
        x = 13,
        y = 1.05,
        yref = "paper",
        text = "Peak Hours",
        showarrow = FALSE,
        font = list(size = 11, color = "#FF8C00")
      )
    )
  )

hourly_orders
```

### Weekly Order Pattern on Instacart

```{r}
weekly_orders =
  instacart_df |>
  count(order_day_name) |>
  mutate(
    pct_of_total = round(n / sum(n) * 100, 1),
    # Reorder days from Monday to Sunday
    order_day_name = factor(
      order_day_name,
      levels = c("Monday", "Tuesday", "Wednesday", "Thursday", 
                 "Friday", "Saturday", "Sunday")
    )
  ) |>
  arrange(order_day_name) |>
  plot_ly(
    x = ~order_day_name,
    y = ~n,
    type = "scatter",
    mode = "lines+markers",
    line = list(
      color = "#2ca02c",
      width = 4
    ),
    marker = list(
      size = 12,
      color = "#2ca02c",
      symbol = "circle",
      line = list(color = "white", width = 2)
    ),
    text = ~paste0(
      "<b>", order_day_name, "</b><br>",
      "Orders: ", scales::comma(n), "<br>",
      "Percentage: ", pct_of_total, "%"
    ),
    hovertemplate = "%{text}<extra></extra>"
  ) |>
  layout(
    title = list(
      text = "<b>Weekly Order Pattern on Instacart</b><br><sub>Monday to Sunday shopping trends</sub>",
      font = list(size = 16)
    ),
    xaxis = list(
      title = "Day of Week",
      titlefont = list(size = 14),
      tickangle = 0
    ),
    yaxis = list(
      title = "Number of Orders",
      titlefont = list(size = 14),
      gridcolor = "#E5E5E5",
      tickformat = ","
    ),
    plot_bgcolor = "#FAFAFA",
    paper_bgcolor = "white",
    margin = list(l = 80, r = 50, t = 100, b = 80),
    hovermode = "x unified"
  )

weekly_orders 
```